package com.tbit.main.aop;

import com.tbit.main.constant.PreventDuplication;
import com.tbit.main.exception.BaseException;
import com.tbit.main.util.RedisLockUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * @Author: chen
 * @Description: 接口频次限制
 * @Date: 创建于 10:38 2021/9/28
 */
@Component
@Aspect
public class PreventDuplicationAspect {

    @Autowired
    private RedisLockUtils redisLockUtils;

    /**
     * 定义切点
     */
    @Pointcut("@annotation(com.tbit.main.constant.PreventDuplication)")
    public void preventDuplication() {
    }


    @Before("preventDuplication()")
    public void before(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        //获取请求
        HttpServletRequest request = attributes.getRequest();
        // HttpServletResponse response = attributes.getResponse();
        //判断请求不为空
        Assert.notNull(request, "request cannot be null.");

        //获取执行方法
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();

        //获取防重复提交注解
        PreventDuplication annotation = method.getAnnotation(PreventDuplication.class);

        //获取方法名称
        Signature signature = joinPoint.getSignature();

        if (!(signature instanceof MethodSignature)) {
            throw new RuntimeException("该注解只支持方法");
        }
        // MethodSignature methodSignature = (MethodSignature) signature;

        //获取参数名称
        // String[] params = methodSignature.getParameterNames();
        //获取参数值
        Object[] args = joinPoint.getArgs();

        String[] parameterNames = ((MethodSignature) signature).getParameterNames();
        // 获取token的下标
        int tokenIndex = ArrayUtils.indexOf(parameterNames, "token");
        // 获取token以及方法标记，生成redisKey和redisValue
        /*Object[] args = joinPoint.getArgs();*/
        String token = String.valueOf(args[tokenIndex]);
        // 获取userCode的下标
        int userCodeIndex = ArrayUtils.indexOf(parameterNames, "userCode");
        if (userCodeIndex != -1) {
            // 获取token以及方法标记，生成redisKey和redisValue
            /*Object[] args = joinPoint.getArgs();*/
            String userCode = String.valueOf(args[userCodeIndex]);
            token = token + userCode;
        }

        // 获取userCodes的下标
        int userCodesIndex = ArrayUtils.indexOf(parameterNames, "userCodes");
        if (userCodesIndex != -1) {
            // 获取token以及方法标记，生成redisKey和redisValue
            /*Object[] args = joinPoint.getArgs();*/
            String userCodes = String.valueOf(args[userCodesIndex]);
            token = token + userCodes;
        }

        /**请求类名*/
        String className = joinPoint.getTarget().getClass().getName();
        className = className.substring(className.lastIndexOf("."));

        /**请求接口方法*/
        String pointName = signature.getName();

        /**缓存key*/
        String redisKey = "main." + token + className + "." + pointName;
        String redisValue = "1";
        if (!redisLockUtils.lock(redisKey, redisValue, annotation.expireSeconds())) {
            throw new BaseException("System.repeated.request");
        }
    }

}
